package com.example.poc.security;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import com.example.poc.exceptions.ResourceNotFoundException;

import net.minidev.json.JSONObject;

@ControllerAdvice
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
  @Override
  public void commence(HttpServletRequest request, HttpServletResponse response,
      AuthenticationException authenticationException)
      throws IOException, ServletException {
    // 401
    setResponseError(request, response, HttpServletResponse.SC_UNAUTHORIZED,
        String.format("Authentication Failed: %s", authenticationException.getMessage()));
  }

  @ExceptionHandler(value = { AccessDeniedException.class })
  public void commence(HttpServletRequest request, HttpServletResponse response,
      AccessDeniedException accessDeniedException) throws IOException {
    // 403
    setResponseError(request, response, HttpServletResponse.SC_FORBIDDEN,
        String.format("Authorization Failed: %s", accessDeniedException.getMessage()));
  }

  @ExceptionHandler(value = { ResourceNotFoundException.class })
  public void commence(HttpServletRequest request, HttpServletResponse response,
      ResourceNotFoundException resourceNotFoundException)
      throws IOException {
    // 404
    setResponseError(request, response, HttpServletResponse.SC_NOT_FOUND,
        String.format("Not Found: %s", resourceNotFoundException.getMessage()));
  }

  @ExceptionHandler(value = { Exception.class })
  public void commence(HttpServletRequest request, HttpServletResponse response, Exception exception)
      throws IOException {
    // 500
    setResponseError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
        String.format("Internal Server Error: %s", exception.getMessage()));
  }

  private void setResponseError(
    HttpServletRequest request,
    HttpServletResponse response,
    int errorCode,
    String errorMessage
  ) throws IOException {
    JSONObject jsonResponse = new JSONObject();
    String timeStamp = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).format(LocalDateTime.now());
    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    response.setStatus(errorCode);
    jsonResponse.put("code", Integer.valueOf(errorCode));
    jsonResponse.put("message", errorMessage);
    jsonResponse.put("timestamp", timeStamp);
    response.getWriter().write(jsonResponse.toJSONString());
    response.getWriter().flush();
    response.getWriter().close();
  }
}